/**
 * @filename:PpBomServiceImpl Sep 23, 2024
 * @project Wonder Vue Admin Api  1.1.0
 * Copyright(c) 2022 Wonder Co. Ltd.
 * All right reserved.
 */
package com.wonder.app.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.utils.VtuzxUtil;
import com.wonder.admin.service.IVtuzxKingdeeService;
import com.wonder.app.domain.*;
import com.wonder.app.mapper.MoldAndInspectDao;
import com.wonder.app.mapper.MoldMaterialDao;
import com.wonder.app.mapper.PrdInstockDao;
import com.wonder.app.mapper.SfcProplanDao;
import com.wonder.app.request.MoldMaterialRequest;
import com.wonder.app.service.MaterialService;
import com.wonder.app.service.MoldInspectService;
import com.wonder.app.service.MoldMaterialService;
import com.wonder.bean.kingdee.VtuzxKingdeeCloudClient;
import com.wonder.bean.kingdee.xqc.VtuzxArrayList;
import com.wonder.common.utils.MapToEntity;
import com.wonder.constant.BillType;
import com.wonder.constant.IXqcConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.web3j.abi.datatypes.primitive.Int;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @Description:TODO(模具服务实现)
 *
 * @version: 1.1.0
 * @author: Wonder
 *
 */
@Service
public class MoldMaterialServiceImpl  extends ServiceImpl<MoldMaterialDao, MoldMaterial> implements MoldMaterialService {

    private static final Logger _logger = LoggerFactory.getLogger(PurInServiceImpl.class);
    @Autowired
    private MoldMaterialDao moldMaterialDao;
    @Autowired
    private MoldMaterialService moldMaterialService;
    @Autowired
    private IVtuzxKingdeeService vtuzxKingdeeService;

    @Autowired
    private MoldInspectService moldInspectService;

    @Autowired
    private MoldAndInspectDao moldAndInspectDao;

    @Autowired
    private SfcProplanDao sfcProplanDao;

    @Autowired
    private PrdInstockDao prdInstockDao;

    /**
     * 验证模具信息
     * @param moldMaterial
     * @param type
     * @return
     */
    @Override
    public String validate(MoldMaterial moldMaterial,String type){


        return "";
    }

    @Override
    public IPage<MoldMaterial> selectList(MoldMaterialRequest request, Page<MoldMaterial> page) {
        LambdaQueryWrapper<MoldMaterial> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        if (null != request.getId()) {
            lambdaQueryWrapper.eq(MoldMaterial::getId, request.getId());
        }
        if (request.getMaterialNo() != null){
            lambdaQueryWrapper.like(MoldMaterial::getMaterialNo,request.getMaterialNo());
        }
        if (request.getMaterialName() != null){
            lambdaQueryWrapper.like(MoldMaterial::getMaterialName,request.getMaterialName());
        }
        if (request.getStockNo() != null){
            lambdaQueryWrapper.like(MoldMaterial::getStockNo,request.getStockNo());
        }
        if (request.getStockName() != null){
            lambdaQueryWrapper.like(MoldMaterial::getStockName,request.getStockName());
        }
        if (request.getLocationNo() != null){
            lambdaQueryWrapper.like(MoldMaterial::getLocationNo,request.getLocationNo());
        }
        if (request.getLocationName() != null){
            lambdaQueryWrapper.like(MoldMaterial::getLocationName,request.getLocationName());
        }
        if (request.getCreateTime() != null){
            Date[] orderDate = request.getCreateTime();
            if(orderDate.length>0)
                lambdaQueryWrapper.ge(MoldMaterial::getCreateTime, orderDate[0]);
            if(orderDate.length==2)
                lambdaQueryWrapper.le(MoldMaterial::getCreateTime,orderDate[1]);

        }
        lambdaQueryWrapper.orderByDesc(MoldMaterial::getId);
        Page<MoldMaterial> selectPage = this.baseMapper.selectPage(page, lambdaQueryWrapper);
        return selectPage;
    }

    @Override
    public Map<String, Object> getmoldmaDetail(Map<String, Object> map) {
            String id = map.get("id").toString();
            List<MoldAndInspect> maiList = moldAndInspectDao.selectList(new LambdaQueryWrapper<MoldAndInspect>()
                    .eq(MoldAndInspect::getMoldId,id));
            Map<String,Object> data = new HashMap<>();
            data.put("dataList",maiList);
            return data;

    }

    /**
     * 入库时创建模具列表
     * @param userName
     * @param map
     * @return
     * @throws Exception
     */
    @Override
    public boolean createMoldMaterial(String userName, Map<String, Object> map)throws Exception{
        VtuzxKingdeeCloudClient client = vtuzxKingdeeService.loginKingdee();
        Map<String,Object> planData = VtuzxUtil.getObject(map,"planData");
        String materialNo = VtuzxUtil.getString(map,"materialNo");//物料编码
        String stockNo = VtuzxUtil.getString(map,"stockNo");//仓库编码
        String locationNo = VtuzxUtil.getString(map,"LocationNo");//仓位编码
        int firstIns = 0;
        int continueIns = 0;
        int erpCl = 0;
        MoldMaterial moldMaterial = new MoldMaterial();
        if (checkMold(stockNo,locationNo) <=0){
            //查询物料信
            List<VtuzxMap> materialQuery = vtuzxKingdeeService.query(client, "BD_MATERIAL", new VtuzxArrayList<>(
                            "F_VKFP_SJCS",//首检次数
                            "F_VKFP_XJCS",//续检次数
                            "FErpClsID"//物料属性
                    ),
                    String.format("FNumber = '%s'", materialNo), null, 0, 1);
            if (!VtuzxUtil.isEmpty(materialQuery)) {
                firstIns = VtuzxUtil.getInt(materialQuery.get(0),"F_VKFP_SJCS");
                continueIns = VtuzxUtil.getInt(materialQuery.get(0),"F_VKFP_XJCS");
                erpCl = VtuzxUtil.getInt(materialQuery.get(0),"FErpClsID");
            }
            moldMaterial.setMaterialNo(materialNo);//物料编码
            moldMaterial.setMaterialName(VtuzxUtil.getString(map,"MaterialName"));//物料名称
            moldMaterial.setCreateTime(new Date());//创建日期
            moldMaterial.setSpecification(VtuzxUtil.getString(map,"Specification"));//规格型号
            moldMaterial.setUnitName(VtuzxUtil.getString(map,"UnitName"));//单位名称
            moldMaterial.setUnitNumber(VtuzxUtil.getString(map,"UnitNumber"));//单位编码
            moldMaterial.setStatus(0);//状态，入库时默认在库
            moldMaterial.setErpCl(erpCl);//物料属性
            moldMaterial.setFirstIns(firstIns);//首检次数
            moldMaterial.setContinueIns(continueIns);//续检次数
            moldMaterial.setStockNo(VtuzxUtil.getString(map,"StockNo"));
            moldMaterial.setStockName(VtuzxUtil.getString(map,"StockName"));
            moldMaterial.setLocationNo(VtuzxUtil.getString(map,"LocationNo"));
            moldMaterial.setLocationName(VtuzxUtil.getString(map,"LocationName"));
            moldMaterial.setUseAllCount(0);
            moldMaterial.setUseCount(0);
            moldMaterial.setInspectCount(0);
            moldMaterial.setInspectStatus(2);//检验状态2正常
        }else {
            throw new RuntimeException(String.format("当前仓库%s仓位%s已有模具信息，无法重复入库",stockNo,locationNo));
        }

        return moldMaterialService.save(moldMaterial);
    }

    /**
     * 获取模具信息根据仓库仓位
     * @param map
     * @return
     */
    @Override
    public Map<String, Object> getMoldMaterial(Map<String, Object> map) throws Exception{
        String locationNo = VtuzxUtil.getString(map,"locationNo");//仓位编码
        //获取模具唯一仓位信息(查询的时候加上状态判断检查状态正常，数据状态在库)
        MoldMaterial moldMaterial = moldMaterialDao.selectOne(new LambdaQueryWrapper<MoldMaterial>()
                .eq(MoldMaterial::getLocationNo,locationNo)
                .ne(MoldMaterial::getStatus,2));//单据状态不是报废的
//                .eq(MoldMaterial::getStatus,0)//单据状态在库
//                .eq(MoldMaterial::getInspectStatus,2));//检查状态正常


        if (VtuzxUtil.isEmpty(moldMaterial)){
            throw new RuntimeException("当前仓位不存在模具或者模具不在库");
        }
        //判断是已经是临时领用‘
        if (moldMaterial.getIsTemp()){
            throw new RuntimeException(String.format("模具已被占用,关联工单号:%s,领用人:%s",moldMaterial.getAssBillNo(),moldMaterial.getPickUser()));
        }
        //判断模具是否在库,提示时加上谁领用的
        if(moldMaterial.getStatus() != 0){
            throw new RuntimeException(String.format("模具已经出库,关联工单号:%s,领用人:%s",moldMaterial.getAssBillNo(),moldMaterial.getPickUser()));
        }
        //判断检查状态
        if(moldMaterial.getInspectStatus() != 2){
            throw new RuntimeException(String.format("模具正在维修,领用人:%s",moldMaterial.getPickUser()));
        }
        Map<String,Object> data = new HashMap<>();
        data.put("data",moldMaterial);
        return data;
    }

    /**
     * 修改模具状态
     * @param
     * @return
     */
    public boolean updateMoldStatus(MoldMaterial moldMaterial,String type) {
        if ("检查出库".equals(type)){//修改模具状态为出库，检查状态为检查
            moldMaterial.setStatus(1);
            moldMaterial.setInspectStatus(0);
            moldMaterial.setInspectCount(moldMaterial.getInspectCount() + 1);//检查次数+1
        } else if ("检查正常".equals(type)){//使用次数归0，数据状态在库，检查状态正常(2)
            moldMaterial.setStatus(0);
            moldMaterial.setInspectStatus(2);
            moldMaterial.setUseCount(0);

        } else if ("检查报废".equals(type)){//数据状态报废，检查状态报废
            moldMaterial.setStatus(2);
            moldMaterial.setInspectStatus(3);
        } else if("检查维修".equals(type)){
            moldMaterial.setInspectStatus(1);
        } else if ("维修完成".equals(type)){//使用次数归0，数据状态在库，检查状态正常(2),维修次数加1
            moldMaterial.setStatus(0);
            moldMaterial.setInspectStatus(2);
            moldMaterial.setUseCount(0);
            moldMaterial.setMaintenCount(moldMaterial.getMaintenCount() + 1);
        }
        return moldMaterialService.saveOrUpdate(moldMaterial);
    }

    @Override
    public boolean pickMoldByorderNo(String userName, Map<String, Object> map) throws Exception {
        Map<String,Object> moldMap = VtuzxUtil.getObject(map,"moldData");
        Map<String,Object> planData = VtuzxUtil.getObject(map,"planData");
        String billNo = VtuzxUtil.getString(planData,"billNo");//工序计划号
        MoldMaterial moldMaterial = MapToEntity.mapToBean(moldMap,MoldMaterial.class);
        Boolean aBoolean = pickMoldStatus(userName,moldMaterial, billNo,"pick");
        //修改模具的状态为出库状态，模具上绑定工序计划单号

        return aBoolean;
    }

    /**
     * 工序计划归还模具
     * @param userName
     * @param map
     * @return
     * @throws Exception
     */
    @Override
    public boolean ReturnMoldByorderNo(String userName, Map<String, Object> map) throws Exception {
        String billNo = VtuzxUtil.getString(map,"billNo");//工序计划号
        String locationNo = VtuzxUtil.getString(map,"locationNo");//仓位编号
        //TODO 需要校验仓位是否是正确的仓位信息
        Map<String,Object> moldData = VtuzxUtil.getObject(map,"moldData");//模具信息
        MoldMaterial moldMaterial = MapToEntity.mapToBean(moldData,MoldMaterial.class);//转换成实体类
        //判断当前仓位是否有模具，有的话不能归还。没有的话归还模具，修改模具对应的仓位信息以及增加模具对应的使用次数
        MoldMaterial moldMaterialByLoc =  moldMaterialDao.selectOne(new LambdaQueryWrapper<MoldMaterial>()
                .eq(MoldMaterial::getLocationNo,locationNo)
                .eq(MoldMaterial::getStatus,0));//数据状态在库
        if (!VtuzxUtil.isEmpty(moldMaterialByLoc)){
            throw new RuntimeException(String.format("当前仓位存在模具:%s",moldMaterialByLoc.getSpecification()));
        }
        //并且修改仓位的信息(不增加模具使用次数,模具使用次数在入库时增加)
        moldMaterial.setStatus(0);
        moldMaterial.setAssBillNo("");
        moldMaterial.setPickUser("");
        moldMaterial.setLocationNo(locationNo);//赋值仓位信息
        moldMaterial.setLocationName(locationNo);
        //查询入库单获取入库数量

        boolean b = moldMaterialService.updateById(moldMaterial);
//        Boolean aReturn = pickMoldStatus(userName,moldMaterial, billNo, "return");
        //归还模具校验模具是否到达检修次数(如果到达的话生成检修单)
        Boolean aBoolean = checkMoldUserCount(moldMaterial);
        if (aBoolean){//需要检查生成检查单
            moldInspectService.createInspect(userName,moldMaterial);
        }

        return b;
    }

    /**
     * 删除领用模具的临时信息
     * @param userName
     * @param map
     * @return
     * @throws Exception
     */
    @Override
    public boolean deletePickMoldTemp(String userName, Map<String, Object> map) throws Exception {
        int id = VtuzxUtil.getInt(map,"id");
        MoldMaterial moldMaterial = moldMaterialDao.selectById(id);
        moldMaterial.setIsTemp(false);
        moldMaterial.setAssBillNo("");
        moldMaterial.setPickUser("");//领用人员清空
        boolean b = moldMaterialService.updateById(moldMaterial);
        return b;
    }

    /**
     * 审核领用模具
     * @param userName
     * @param map
     * @return
     * @throws Exception
     */
    @Override
    public boolean auditPickMold(String userName, Map<String, Object> map) throws Exception {
        List<Map<String,Object>> moldMap = VtuzxUtil.getObject(map,"moldList");
        Map<String,Object> planData = VtuzxUtil.getObject(map,"planData");
        String billNo = VtuzxUtil.getString(planData,"billNo");//工序计划号
        SfcProplan sfcProplan = sfcProplanDao.selectOne(new LambdaQueryWrapper<SfcProplan>()
                .eq(SfcProplan::getBillNo, billNo));
        List<Long> moldIdList = new ArrayList<>();//领用的模具id集合
        List<MoldMaterial> moldMaterialList = new ArrayList<>();
        for (Map<String,Object> data : moldMap){
            //修改临时数据状态，调整为出库状态
            MoldMaterial moldMaterial = MapToEntity.mapToBean(data,MoldMaterial.class);
            Long id = moldMaterial.getId();
            moldMaterial.setIsTemp(false);
            moldMaterial.setStatus(1);
            moldMaterialList.add(moldMaterial);
            if (!moldIdList.contains(id)){
                moldIdList.add(id);
            }
        }
        //将idlist转成字符串
        String idStr = moldIdList.stream()
                .map(String::valueOf)
                .collect(Collectors.joining(","));
        //工序计划修改是否领用模具状态
        sfcProplan.setMoldStatus(true);
        if (!VtuzxUtil.isEmpty(sfcProplan.getMoldId())){
            sfcProplan.setMoldId(sfcProplan.getMoldId()+ "," + idStr);
        } else {
            sfcProplan.setMoldId(idStr);
        }

        sfcProplanDao.updateById(sfcProplan);
        boolean b = moldMaterialService.saveOrUpdateBatch(moldMaterialList);
        return b;
    }

    /**
     * 入库后增加模具的使用次数
     * @param prdInstock
     * @return
     * @throws Exception
     */
    @Override
    public Boolean addMoldUserCount(PrdInstock prdInstock) throws Exception {
        String proplanno = prdInstock.getPROPLANNO();//工序计划单号
        SfcProplan sfcProplan = sfcProplanDao.selectOne(new LambdaQueryWrapper<SfcProplan>()
                .eq(SfcProplan::getBillNo, proplanno));
        String moldId = sfcProplan.getMoldId();//使用的模具
        //如果为空的话说明当前工单没有领用模具
        if (VtuzxUtil.isEmpty(moldId)){
            return true;
        }
        //将字符串类型转成List
        List<Integer>  moldIdList = Arrays.stream(moldId.split(","))
                .map(String::trim)//去掉元素空格
                .map(Integer::parseInt)//转成Integer
                .distinct()//去重
                .collect(Collectors.toList());
        List<MoldMaterial> moldMaterialList = moldMaterialDao.selectBatchIds(moldIdList);
        for (MoldMaterial moldMaterial : moldMaterialList){
            moldMaterial.setUseCount((int) (moldMaterial.getUseCount() + prdInstock.getFQTY()));
            moldMaterial.setUseAllCount((int) (moldMaterial.getUseAllCount() + prdInstock.getFQTY()));
            checkMoldUserCount(moldMaterial);//校验模具是否需要检修
        }
        boolean b = moldMaterialService.saveOrUpdateBatch(moldMaterialList);

        return b;
    }

    /**
     * 金蝶其他出库传到中台做模具入库
     * @param map
     * @return
     * @throws Exception
     */
    @Override
    public boolean audit(JSONObject map) throws Exception {
        _logger.info("金蝶其他出库单"+ map.toString());
        JSONArray erceives = map.getJSONArray("OtherList");
        List<MoldMaterial> moldMaterialList = new ArrayList<>();
        for (Object obj : erceives) {
            JSONObject jsonObject = (JSONObject) obj;
            //将json直接转成实体类
            MoldMaterial moldMaterial = jsonObject.toBean(MoldMaterial.class);
            moldMaterial.setCreateTime(new Date());
            moldMaterial.setIsTemp(false);
            moldMaterialList.add(moldMaterial);
        }
        boolean res = moldMaterialService.saveOrUpdateBatch(moldMaterialList);
        return res;
    }

    /**
     * 工序计划领用或者归还模具的时候修改模具的状态
     * @return
     */
    private Boolean pickMoldStatus( String userName, MoldMaterial moldMaterial, String billNo,String type) throws Exception{
        if ("pick".equals(type)){
//            moldMaterial.setStatus(1);
            moldMaterial.setIsTemp(true);//临时数据(模具领用是临时的)
            moldMaterial.setAssBillNo(billNo);
            moldMaterial.setPickUser(userName);//领用人员
        } else {//工序归还模具，增加模具的使用次数(按照入库数量增加)
            moldMaterial.setStatus(0);
            moldMaterial.setAssBillNo("");
            moldMaterial.setPickUser("");
            //查询入库单获取入库数量
            Double qty = 0.0;
            List<PrdInstock> prdInstocks = prdInstockDao.selectList(new LambdaQueryWrapper<PrdInstock>()
                    .eq(PrdInstock::getPROPLANNO, billNo));
            if (!VtuzxUtil.isEmpty(prdInstocks)){
                for (PrdInstock prdInstock : prdInstocks){
                    qty += prdInstock.getFQTY();
                }
            }

            moldMaterial.setUseCount((int) (moldMaterial.getUseCount() + qty));
            moldMaterial.setUseAllCount((int) (moldMaterial.getUseAllCount() + qty));

        }

        boolean res = moldMaterialService.updateById(moldMaterial);
        return res;
    }

    /**
     * 检查模具在当前仓库仓位是否存在数据
     * @param stockNo
     * @param locationNo
     * @return
     */
    private long checkMold(String stockNo,String locationNo){
        //查询当前仓库仓位是否已有已经入库并且状态为在库的模具
        QueryWrapper<MoldMaterial> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("stockNo",stockNo)
                .eq("locationNo",locationNo)
                .eq("status",0);
        long count =this.count(queryWrapper);
        return count;
    }

    /**
     * 校验模具是否到达检修次数
     * @param moldMaterial
     * @return
     */
    private Boolean checkMoldUserCount(MoldMaterial moldMaterial){
        int useCount = moldMaterial.getUseCount();//当前使用次数
        int inspectCount = moldMaterial.getInspectCount();//检查次数
        int firstIns = moldMaterial.getFirstIns();//首检次数
        int continueIns = moldMaterial.getContinueIns();//续检次数
        //检查次数小于1的情况下根据首检次数判断，大于1根据续检次数判断
        if(inspectCount < 1){
            if (useCount >= firstIns){
                return true;
            }
        } else {//判断续检次数
            if (useCount >= continueIns){
                return true;
            }
        }

        return false;
    }

}